/**
 * \file kernel/syscall.c
 * \author Davide Gessa
 * \date 10-12-09
 */
#include <syscall.h>
#include <types.h>
#include <arch.h>
#include <debug.h>
#include <util.h>
#include <task/task.h>
#include <task/term.h>
#include <driver.h>
#include <video.h>
#include <driver.h>
#include <fs/fs.h>
#include <main.h>

/**
 * Lista delle syscalls
 */
syscall_t syscalls[] =
	{
		// System misc
		{ .name="sysinfo_get", .call = sysinfo_get },		///> sys_info_get
		//{ .name="shutdown", .call = shutdown },				///> sys_shutdown
	};


/**
 * Numero totale delle syscalls
 */
uint32_t syscalls_number = sizeof(syscalls) / sizeof(syscall_t);


/**
 * Effetua una chiamata ad una call
 * 
 * \param call numero della syscall
 * \param ebx parametro 1
 * \param ecx parametro 2
 * \param edx parametro 3
 */
int syscall_call(uint32_t call, uint32_t ebx, uint32_t ecx, uint32_t edx)
{
	regs_t reg;
	reg.eax = call;
	reg.ebx = ebx; 
	reg.ecx = ecx; 
	reg.edx = edx; 
	asm("movl %0, %%eax\n\t": : "g" (&reg));
	
	asm ("int %0\n" : : "g" (SYSCALL_INT));
	
	asm ("movl %%eax, %0\n\t" : "=r" (reg.eax));
	return reg.eax;
}


/**
 * Handler delle chiamate alla syscall
 * 
 * \param r tutti i registri salvati al momento dell'interruzione
 */
void syscall_callback(regs_t *r)
{	
	regs_t *reg;
	int ret;
	
	// Preleva gli argomenti
	asm ("movl %%eax, %0\n\t" : "=r" (reg));
		 
	
	if(reg->eax > syscalls_number)
		return;
		
	ret = syscalls[reg->eax].call(reg->ebx, reg->ecx, reg->edx);		
	
	// Restituisce il valore di ritorno
	asm("movl %0, %%eax\n\t": : "g" (ret)); 
}



/**
 * Inizializza le syscall
 */
void syscall_init()
{
	DEBUGP("syscall_init()\n");
}


